package com.pactera.jep.service.sys.security.spring.conf;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 判断用户是否有足够的权限访问目标url
 * 
 * @author ghost
 *
 */
@Component
public class UrlAccessDecisionManager implements AccessDecisionManager {

	private final static Logger logger = LoggerFactory.getLogger(UrlAccessDecisionManager.class);

	@Value("${authentication.profile:local}")
	private String authenticationProfile;

	@Override
	public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
			throws AccessDeniedException, InsufficientAuthenticationException {
		if (configAttributes == null || configAttributes.size() == 0) {
			logger.debug("用户访问无需权限的url");
		} else {
			// TODO:修改权限，对所有路径全部放开权限不加验证
			return;
			/*// 获取地址需要的权限
			List<String> neededRoles = configAttributes.stream().map(ConfigAttribute::getAttribute)
					.collect(Collectors.toList());
			// 获取用户的权限
			List<String> userRoles = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority)
					.collect(Collectors.toList());
			// 对authenticationProfile进行判断处理
			if (StringUtils.isBlank(authenticationProfile) || !"sso".equals(authenticationProfile)) {
				// 所有非SSO登录的情况目前都算作本地登录，这个时候只需要对用户是否登录进行验证
				if (authentication instanceof AnonymousAuthenticationToken) {
					logger.error("用户未登录!");
					throw new BadCredentialsException("匿名用户尝试访问需要登录才能访问的url");
				}
				if (neededRoles.contains("ROLE_SSO")) {
					authentication.getPrincipal();
					logger.error("用户{}在本地登录情况下尝试访问sso接口.", authentication.getName());
					throw new AccessDeniedException("无权访问此地址!");
				}
				if (neededRoles.contains("ROLE_LOGIN")) {
					logger.debug("登录用户访问只需要登录就可以访问的地址.");
					return;
				} else {
					// 首先去需要的权限和用户权限之间的交集
					neededRoles.retainAll(userRoles);
					// 如果交集不为空，说明用户有权限访问
					if (neededRoles.isEmpty()) {
						logger.debug("用户没有访问指定url的权限.");
						throw new AccessDeniedException("无权访问此地址!");
					}
				}
			} else {
				// 在sso登录情况下屏蔽掉/requireLogin接口
				if (neededRoles.contains("ROLE_LOCAL")) {
					// TODO:获取到用户数据
					logger.debug("用户在sso登录情况下尝试访问local接口.");
					throw new AccessDeniedException("无权访问此接口!");
				} else if (neededRoles.contains("ROLE_SSO_CALLBACK")) {
					// 对sso验证回调接口放行
					logger.debug("对sso接口放行");
					return;
				} else if (neededRoles.contains("ROLE_SSO")) {
					// 要访问其它的接口，在sso登录的情况下必须要判断用户是否是已经通过cas验证
					HttpServletRequest request = getRequest();
					if (request == null || StringUtils.isEmpty(request.getHeader("auth_info"))) {
						logger.error("无法获取到请求信息或用户验证信息，拒绝处理!");
						throw new AccessDeniedException("请求非法!");
					}
					logger.debug("用户经过验证，可以访问其它接口.");
					return;
				} else {
					logger.error("不能识别的权限：{}", neededRoles.stream().collect(Collectors.joining(",")));
					throw new AccessDeniedException("无权访问此接口!");
				}
			}*/
		}
	}

	@Override
	public boolean supports(ConfigAttribute attribute) {
		return true;
	}

	@Override
	public boolean supports(Class<?> clazz) {
		return true;
	}

	/**
	 * 获取当前请求的session，我们可以从session中获取相关的数据
	 * 
	 * @return
	 */
	private HttpServletRequest getRequest() {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();
		return request;
	}

}
